//
//  ShaderSrc.cpp
//  STDRenderSDK
//
//  Created by 陈学明 on 2023/3/13.
//  Copyright © 2023 陈学明. All rights reserved.
//

#include "STDSShaderStream.hpp"
#include <Basic/graphic/STDSOpenGL.h>

const char *gl_shader_vex_2D = SHADER_SRC(
    SHDR_VERT_HEAD_NORM

    void main() {
        vPosition = vec4(aPos.xyz, 1.0);
        gl_Position = vPosition;
        vTexCoord = aTexCoord;
    }
);

const char *gl_shader_vex_3D = SHADER_SRC(
        SHDR_VERT_HEAD_NORM
        uniform mat4 uMatTex;
        uniform mat4 uMatVex;
        void main() {
            vPosition = uMatVex * aPos;
            gl_Position = vPosition;
            vTexCoord = (uMatTex * vec4(aTexCoord, 0.0, 1.0)).xy;
        }
);

const char *gl_fra_skin_delect = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform sampler2D portraitTexture;

    float rgb_max(vec3 rgb) {
        return max(rgb.r, max(rgb.g, rgb.b));
    }


    float rgb_min(vec3 rgb) {
        return min(rgb.r, min(rgb.g, rgb.b));
    }


    vec3 rgb2hsl(vec3 rgb) {
        float rgbmax = rgb_max(rgb);
        float rgbmin = rgb_min(rgb);
        vec3 hsl = vec3(0.);
        hsl.z = (rgbmax + rgbmin) / 2.;
        if (rgbmax == rgbmin) {
            hsl.y = 0.;
            hsl.x = -1.;
        } else {
            float delta = rgbmax-rgbmin;
            hsl.y = mix(delta/(2.-rgbmax-rgbmin), delta/(rgbmax+rgbmin), step(hsl.z, .5));
            if (delta == 0.) delta = 1.;
            if (rgb.r == rgbmax) hsl.x = (rgb.g-rgb.b)/delta;
            else if (rgb.g == rgbmax) hsl.x = 2. + (rgb.b-rgb.r)/delta;
            else hsl.x = 4.+(rgb.r-rgb.g)/delta;
            hsl.x /= 6.;
            hsl.x = mix(hsl.x+1., hsl.x, step(0., hsl.x));
        }
        return hsl;
    }

    float hsl_value(float n1, float n2, float hue) {
        if (hue < 0.){
            hue = hue + 6.;
        } else if (hue > 6.){
            hue = hue - 6.;
        }
        if (hue > 4.){
            return n1;
        } else if (hue > 3.){
            return n1 + (n2 - n1)*(4.-hue);
        } else if (hue > 1.){
            return n2;
        } else {
            return n1 + (n2 - n1) * hue;
        }
    }

    vec3 hsl2rgb(vec3 hsl) {
        vec3 rgb = vec3(0.);
        if (hsl.y == 0.) {
            rgb.r = hsl.z;
            rgb.g = hsl.z;
            rgb.b = hsl.z;
        } else {
            float m2 = mix(hsl.z + hsl.y - hsl.z*hsl.y, hsl.z*(1.+hsl.y), step(hsl.z, .5));
            float m1 = 2.*hsl.z-m2;
            rgb.r = hsl_value(m1, m2, hsl.x * 6. + 2.);
            rgb.g = hsl_value(m1, m2, hsl.x * 6.);
            rgb.b = hsl_value(m1, m2, hsl.x * 6. - 2.);
        }
        return rgb;
    }

    float rgb2gray(vec3 c){
        return dot(c, vec3(0.299, 0.587, 0.114));
    }

    void main(){

        vec3 origin = vec3(300./360., 375./360., 450./360.);

        vec4 color = texture2D(inputImageTexture, vTexCoord);

        vec4 portrait = texture2D(portraitTexture, vTexCoord);

        vec3 hsl = rgb2hsl(color.rgb);

        float h = mix(hsl.x + 1., hsl.x, step(origin.z - 1., hsl.x));

        float s = (rgb_max(color.rgb) - rgb_min(color.rgb)) / (rgb_max(color.rgb) + rgb_min(color.rgb) + 0.001);

        float a = portrait.a;

        if (h > origin.x && h < origin.z){
            float sat_s = max(0.4 - abs(s - 0.4), 0.) / 0.4;
            float hue_s = 1.0 - abs(h - origin.y) * 360. / 75.;
            a = min(sat_s * hue_s * a, 0.5);
        } else {
            a = 0.0;
        }

        gl_FragColor = vec4(a);
    }

);

const char *gl_fra_default = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    void main() {
        vec4 src = texture2D(uTexture, vTexCoord);
        gl_FragColor = vec4(src.r, src.g, src.b, src.a);
    }
);

const char *gl_fra_maskKey = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    uniform sampler2D uMask;
    void main() {
        vec4 src = texture2D(uTexture, vTexCoord);
        vec4 mask = texture2D(uMask, vTexCoord);
        gl_FragColor = src*mask.r;
    }
);

/// ----------- 拼图
const char *gl_fra_puzzleUnit = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    uniform vec4 insetsEdge;
    uniform mat4 uTexTransMat;
   
   vec4 getCol(vec2 uv) {
       vec4 targetUV = uTexTransMat*vec4(uv, 0.0, 1.0);
       return texture2D(uTexture, targetUV.xy);
   }
                                           
    void main() {
        vec4 src = getCol(vTexCoord);
        vec2 uv = vTexCoord;
        float smoothLeft = smoothstep(0.0, abs(insetsEdge.x + 0.0001), uv.x);
        float smoothTop = smoothstep(0.0, abs(insetsEdge.y + 0.0001), 1.0 - uv.y);

        float smoothRight = smoothstep(0.0, abs(insetsEdge.z + 0.0001), 1.0 - uv.x);
        float smoothBottom = smoothstep(0.0, abs(insetsEdge.w + 0.0001), uv.y);
        float sm = smoothLeft*smoothTop*smoothRight*smoothBottom;

        sm = pow(sm, 0.5);
        gl_FragColor = vec4(src.rgb, src.a*sm);
    }
);

const char *gl_fra_puzzleStarsMask = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform vec4 insetsEdge;
    void main() {
        vec2 uv = vTexCoord;
        float smoothLeft = smoothstep(0.0, abs(insetsEdge.x + 0.0001), uv.x);
        float smoothTop = smoothstep(0.0, abs(insetsEdge.y + 0.0001), 1.0 - uv.y);

        float smoothRight = smoothstep(0.0, abs(insetsEdge.z + 0.0001), 1.0 - uv.x);
        float smoothBottom = smoothstep(0.0, abs(insetsEdge.w + 0.0001), uv.y);
        float sm = smoothLeft*smoothTop*smoothRight*smoothBottom;
        gl_FragColor = vec4(sm);
    }
);

const char *gl_fra_puzzleStars = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    uniform sampler2D uMask;
    uniform vec2 scale;
                                            
    void main() {
        vec4 src = texture2D(uTexture, (vTexCoord - 0.5) * scale + 0.5);
        vec4 mask = texture2D(uMask, vTexCoord);
        gl_FragColor = vec4(src.rgb/src.a, src.a*(1.0 - mask.r));
    }
);

const char *gl_fra_puzzleBreak = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    uniform vec2 uSize;
    uniform vec4 insetsEdge;
    uniform mat4 uTexTransMat;
   
   vec4 getCol(vec2 uv) {
       vec4 targetUV = uTexTransMat*vec4(uv, 0.0, 1.0);
       return texture2D(uTexture, targetUV.xy);
   }
                                           
    void main() {
        vec4 src = getCol(vTexCoord);
        vec2 uv = vTexCoord;
        float smoothLeft = smoothstep(0.0, abs(insetsEdge.x + 0.0001), uv.x);
        float smoothTop = smoothstep(0.0, abs(insetsEdge.y + 0.0001), 1.0 - uv.y);

        float smoothRight = smoothstep(0.0, abs(insetsEdge.z + 0.0001), 1.0 - uv.x);
        float smoothBottom = smoothstep(0.0, abs(insetsEdge.w + 0.0001), uv.y);
        float sm = smoothLeft*smoothTop*smoothRight*smoothBottom;
        
        float breakIntencity = 1.0;
        breakIntencity *= smoothstep(0.0, insetsEdge.x*2.0, uv.x);
        breakIntencity *= smoothstep(0.0, insetsEdge.y*2.0, 1.0 - uv.y);
        breakIntencity *= smoothstep(0.0, insetsEdge.z*2.0, 1.0 - uv.x);
        breakIntencity *= smoothstep(0.0, insetsEdge.w*2.0, uv.y);
        float a = 0.3 * smoothstep(0.0, 0.3, 1.0 - breakIntencity);
        vec4 target = clamp(src * (1.0-a) + getCol(vTexCoord - 0.02) * a, 0.0, 1.0);
        gl_FragColor = vec4(target.rgb, target.a*sm);
    }
);

const char *gl_fra_puzzleGrain = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    uniform vec2 uSize;
    uniform vec4 insetsEdge;
    uniform mat4 uTexTransMat;
   
   vec4 getCol(vec2 uv) {
       vec4 targetUV = uTexTransMat*vec4(uv, 0.0, 1.0);
       return texture2D(uTexture, targetUV.xy);
   }
                                            
                                            
    float grainFunc(float threshold) {
        vec2 uv = vTexCoord;
        uv = (uv*uSize*2.0 - uSize)/min(uSize.x, uSize.y);
        float arc = radians(45.0);
        float sinArc = sin(arc);
        float cosArc = cos(arc);
        uv = mat2(cosArc, -sinArc, sinArc, cosArc) * uv;

        uv *= 50.0;
        
        uv = fract(uv);
        uv -= 0.5;
        float grain = 1.0 - length(uv);
        return smoothstep(0.0, abs(threshold + 0.0001), abs(grain));
    }

                                           
    void main() {
        vec4 src = getCol(vTexCoord);
        vec2 uv = vTexCoord;
        float smoothLeft = smoothstep(0.0, abs(insetsEdge.x + 0.0001), uv.x);
        float smoothTop = smoothstep(0.0, abs(insetsEdge.y + 0.0001), 1.0 - uv.y);

        float smoothRight = smoothstep(0.0, abs(insetsEdge.z + 0.0001), 1.0 - uv.x);
        float smoothBottom = smoothstep(0.0, abs(insetsEdge.w + 0.0001), uv.y);
        float sm = smoothLeft*smoothTop*smoothRight*smoothBottom;
        float grain = grainFunc(1.0 - sm)*sm;
//        grain = pow(grain, 0.5);
        gl_FragColor = vec4(src.rgb, src.a*grain);
    }
);

const char *gl_fra_puzzleCartoon = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
      uniform sampler2D uSrcTexture;
      uniform sampler2D uMaskTexture;
      uniform sampler2D uCartoonTexture;
                                             
      void main() {
          vec4 src = texture2D(uSrcTexture, vTexCoord);
          vec4 cartoon = texture2D(uCartoonTexture, vTexCoord);
          vec4 mask = texture2D(uMaskTexture, vTexCoord);
          vec4 targetCol = mix(cartoon, src, mask.r);
          gl_FragColor = targetCol;
      }
);

const char *gl_fra_puzzleGlass = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    uniform sampler2D uMask;
   
    vec2 hash(vec2 p ) {
        p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
        return -1.0 + 2.0*fract(sin(p)*43758.5453123);
    }

    float noise(vec2 p ) {
        const float K1 = 0.366025404; // (sqrt(3)-1)/2;
        const float K2 = 0.211324865; // (3-sqrt(3))/6;

        vec2  i = floor( p + (p.x+p.y)*K1 );
        vec2  a = p - i + (i.x+i.y)*K2;
        float m = step(a.y,a.x);
        vec2  o = vec2(m,1.0-m);
        vec2  b = a - o + K2;
        vec2  c = a - 1.0 + 2.0*K2;
        vec3  h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
        vec3  n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
        return dot( n, vec3(70.0) );
    }

    vec2 dist(vec2 pos) {
        float offsetX = noise(pos*90.0*10.0)/2.0;
        float offsetY = noise(pos*90.0*15.0)/2.0;
        vec2 targetUV = pos +  (vec2(offsetX, offsetY)) * 0.04;
        return clamp(targetUV, 0.0, 1.0);
    }
                                           
    void main() {
        vec4 src = texture2D(uTexture, vTexCoord);
        vec4 mask = texture2D(uMask, vTexCoord);
        
        vec4 glassCol = texture2D(uTexture, dist(vTexCoord));
        vec4 targetCol = mix(glassCol, src, mask.r);
        
        gl_FragColor = vec4(targetCol.rgb, src.a);
    }
);

const char *gl_fra_puzzleRainbow = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
      uniform sampler2D uTexture;
      uniform vec2 uSize;
      uniform vec4 insetsEdge;
      uniform mat4 uTexTransMat;
     
      const int kColNum = 7;
      vec3 kRainbows[7];
                                              
      vec4 getCol(vec2 uv) {
         vec4 targetUV = uTexTransMat*vec4(uv, 0.0, 1.0);
         return texture2D(uTexture, targetUV.xy);
      }
                          
      void initiRainbows() {
          kRainbows[0] = vec3(1.0, 0.0, 0.0);
          kRainbows[1] = vec3(1.0, 0.647, 0.0);
          kRainbows[2] = vec3(1.0, 1.0, 0.0);
          kRainbows[3] = vec3(0.0, 1.0, 0.0);
          kRainbows[4] = vec3(0.0, 0.498, 1.0);
          kRainbows[5] = vec3(0.0, 0.0, 1.0);
          kRainbows[6] = vec3(0.545098, 0.0, 1.0);
      }

      vec3 getRainbowCol(float h) {
          float index = h * 6.0;
          vec3 col1 = kRainbows[int(floor(index))];
          vec3 col2 = kRainbows[int(ceil(index))];
          vec3 col = mix(col1, col2, fract(index));
          return col;
      }
                                             
      void main() {
          vec4 src = getCol(vTexCoord);
          vec2 uv = vTexCoord;
          float smoothLeft = smoothstep(0.0, abs(insetsEdge.x + 0.0001), uv.x);
          float smoothTop = smoothstep(0.0, abs(insetsEdge.y + 0.0001), 1.0 - uv.y);

          float smoothRight = smoothstep(0.0, abs(insetsEdge.z + 0.0001), 1.0 - uv.x);
          float smoothBottom = smoothstep(0.0, abs(insetsEdge.w + 0.0001), uv.y);
          float sm = smoothLeft*smoothTop*smoothRight*smoothBottom;
          
          initiRainbows();
          float Z = 1.0;
          vec4 final_colour = src*vec4(getRainbowCol(0.0), src.a);
 
          float unit = 1.0/uSize.x;
          
          for (float j = 1.0; j < 50.0; j+=2.0) {
              Z += 1.0;
              vec4 rainbow = vec4(getRainbowCol(j/50.0), 1.0);
              vec2 targetUV = clamp(vec2(uv.x + j*unit, uv.y), 0.0, 1.0);
              final_colour += getCol(targetUV) * rainbow;
          }
          vec4 rainbow = vec4(final_colour/(Z*0.5));
          vec4 outColor = mix(rainbow, src, pow(sm, 2.0));
          outColor.a *= sm;
          gl_FragColor = outColor;
      }
);

///

const char *gl_fra_SolidColor = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform vec4 uColor;
    void main() {
        gl_FragColor = uColor;
    }
);

const char *gl_fra_skin_lut_delect = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform sampler2D portraitTexture;
    uniform sampler2D skinLutTexture;
    void main() {
        vec4 origin = texture2D(inputImageTexture, vTexCoord);

        vec3 textureColor = origin.rgb;

        float blueColor = textureColor.b * 63.0;
        vec2 quad1;
        quad1.y = floor(floor(blueColor) / 8.0);
        quad1.x = floor(blueColor) - (quad1.y * 8.0);
        vec2 quad2;
        quad2.y = floor(ceil(blueColor) / 8.0);
        quad2.x = ceil(blueColor) - (quad2.y * 8.0);
        vec2 texPos1;
        texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
        texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
        vec2 texPos2;
        texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
        texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
        vec4 newColor1 = texture2D(skinLutTexture, texPos1);
        vec4 newColor2 = texture2D(skinLutTexture, texPos2);
        vec4 newColor = mix(newColor1, newColor2, fract(blueColor));

        gl_FragColor = vec4(newColor * texture2D(portraitTexture, st).a);
    }
);

const char *gl_fra_skin_whiten = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform sampler2D portraitTexture;
    uniform sampler2D lutTexture;
    uniform float strength;

    mat4 contrastMatrix( float contrast )
    {
        float t = ( 1.0 - contrast ) / 2.0;

        return mat4( contrast, 0.0, 0.0, 0.0,
        0.0, contrast, 0.0, 0.0,
        0.0, 0, contrast, 0.0,
        t, t, t, 1.0 );

    }



    vec4 lut(vec4 color, float alpha){
        vec3 textureColor = color.rgb * 15. / 16. + vec3(1. / 32.);

        float blueColor = color.b * 63.0;
        vec2 quad1;
        quad1.y = floor(floor(blueColor) / 8.0);
        quad1.x = floor(blueColor) - (quad1.y * 8.0);
        vec2 quad2;
        quad2.y = floor(ceil(blueColor) / 8.0);
        quad2.x = ceil(blueColor) - (quad2.y * 8.0);

        vec2 texPos1;
        texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
        texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);

        vec2 texPos2;
        texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
        texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);

        vec4 newColor = mix(texture2D(lutTexture, texPos1), texture2D(lutTexture, texPos2), fract(blueColor));

        newColor = contrastMatrix(16. / 15.) * newColor;
        return mix(color, vec4(newColor.rgb, color.w), alpha);
    }


    void main(){

        vec4 color = texture2D(inputImageTexture, vTexCoord);

        float a = texture2D(portraitTexture, vTexCoord).a;

        gl_FragColor = lut(color, min(a * strength, 1.0));
    }
);

const char *gl_fra_mosaic = SHADER_SRC(
       SHDR_FRAG_HEAD_NORM
       uniform sampler2D uTexture;
       uniform vec2 uParams;

       void main() {
           vec2 uv = vTexCoord;
           vec2 params = floor(uParams);
           uv = floor(uv * params + 0.5) / params;

           vec4 outColor = texture2D(uTexture, uv);
           outColor *= outColor.a;
           gl_FragColor = outColor;
       }
);

const char *gl_fra_Tex_Alpha = SHADER_SRC(
      SHDR_FRAG_HEAD_NORM
      uniform sampler2D uTexture;
      uniform float uAlpha;
                                          
      void main() {
          vec4 src = texture2D(uTexture, vTexCoord);
          gl_FragColor = vec4(src.rgb * src.a * uAlpha, src.a * uAlpha);
      }
);

const char *gl_fra_mirror_linear_blend_stds = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture1;
    uniform sampler2D inputImageTexture2;
    uniform float strength;

    void main() {
        vec4 a = texture2D(inputImageTexture1, vTexCoord);

        vec4 b = texture2D(inputImageTexture2, vTexCoord);

        float mask = smoothstep(0.0, 1.0, abs(st.x - 0.5) * 2.0);

        gl_FragColor = mix(a, b, mask * strength);
    }
);

const char *gl_fra_add_blend_stds = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture1;
    uniform sampler2D inputImageTexture2;
    uniform float strength;

    void main() {
        vec4 a = texture2D(inputImageTexture1, vTexCoord);

        vec4 b = texture2D(inputImageTexture2, vTexCoord);

        float mask = smoothstep(0.0, 1.0, abs(st.x - 0.5) * 2.0);

        gl_FragColor = mix(a, b, mask * strength);
    }
);

const char *gl_fra_hardlight_blend_stds = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;

    uniform float opacity;

    void main()
    {
     vec4 base = texture2D(inputImageTexture, vTexCoord);
     vec4 overlay = texture2D(inputImageTexture2, vTexCoord) * opacity;

     float ra;
     if (2.0 * overlay.r < overlay.a) {
         ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
     } else {
         ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
     }

     float ga;
     if (2.0 * overlay.g < overlay.a) {
         ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
     } else {
         ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
     }

     float ba;
     if (2.0 * overlay.b < overlay.a) {
         ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
     } else {
         ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
     }

     float alpha = overlay.a + base.a - overlay.a * base.a;
     gl_FragColor = vec4(ra, ga, ba, alpha);
    }

);

const char *gl_fra_bloom_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM

     uniform sampler2D inputImageTexture1;

     uniform sampler2D inputImageTexture2;

     uniform float opacity;

     uniform float exposure;

     void main() {

         vec3 col1 = texture2D(inputImageTexture1, vTexCoord).rgb;

         vec3 col2 = texture2D(inputImageTexture2, vTexCoord).rgb;

         col1 += col2 * 1.5;
         vec3 result = vec3(1.0) - exp(-col1 * exposure);

         result = pow(result, vec3(1. / 2.2));

         gl_FragColor = vec4(result, 1.0);
     }
);

const char *gl_fra_normal_blend_stds = SHADER_SRC(
      SHDR_FRAG_HEAD_NORM
                                             
      uniform sampler2D inputImageTexture;
      uniform sampler2D inputImageTexture2;

      uniform float opacity;

      void main() {
          vec4 c2 = texture2D(inputImageTexture, vTexCoord);
          vec4 c1 = texture2D(inputImageTexture2, vTexCoord) * opacity;
          vec4 outputColor;
          outputColor.r = c1.r + c2.r * c2.a * (1.0 - c1.a);
          outputColor.g = c1.g + c2.g * c2.a * (1.0 - c1.a);
          outputColor.b = c1.b + c2.b * c2.a * (1.0 - c1.a);
          outputColor.a = c1.a + c2.a * (1.0 - c1.a);
          gl_FragColor = outputColor;
      }

);

const char *gl_fra_lineardodge_blend_stds = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
                                                  
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;
    uniform float opacity;

    vec3 blend(vec4 base, vec4 overlay) {
       return base.rgb + overlay.rgb;
    }

    void main() {
       vec4 texture1Color = texture2D(inputImageTexture, vTexCoord);
       vec4 texture2Color = texture2D(inputImageTexture2, vTexCoord) * opacity;
       float flag1 = float(vTexCoord.x >= 0.0 && vTexCoord.x <= 1.0 && vTexCoord.y >= 0.0 && vTexCoord.y <= 1.0);
       texture2Color = mix(vec4(0.0), texture2Color, flag1);

       float alpha = texture1Color.a + texture2Color.a - texture1Color.a * texture2Color.a;
       vec3 color = blend(texture1Color, texture2Color);
       gl_FragColor = vec4(color, alpha);
    }
);


const char *gl_fra_colorburn_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                                  
     uniform sampler2D inputImageTexture;
     uniform sampler2D inputImageTexture2;

     uniform float opacity;

      vec3 colorburn(vec4 Cb, vec4 Cs) {
          float CbCsAlphaProduct = Cb.a * Cs.a;

          float ra;
          if (Cs.r == 0.0) {
              ra = 0.0;
          } else {
              ra = CbCsAlphaProduct - min(CbCsAlphaProduct,
                                          (CbCsAlphaProduct * Cs.a - Cb.r * Cs.a * Cs.a) / Cs.r);
          }

          float rg;
          if (Cs.g == 0.0) {
              rg = 0.0;
          } else {
              rg = CbCsAlphaProduct - min(CbCsAlphaProduct,
                                          (CbCsAlphaProduct * Cs.a - Cb.g * Cs.a * Cs.a) / Cs.g);
          }

          float rb;
          if (Cs.b == 0.0) {
              rb = 0.0;
          } else {
              rb = CbCsAlphaProduct - min(CbCsAlphaProduct,
                                          (CbCsAlphaProduct * Cs.a - Cb.b * Cs.a * Cs.a) / Cs.b);
          }

          return (1.0 - Cs.a) * Cb.rgb + (1.0 - Cb.a) * Cs.rgb + vec3(ra, rg, rb);
      }

     void main() {
         vec4 textureColor = texture2D(inputImageTexture, vTexCoord);
         vec4 textureColor2 = texture2D(inputImageTexture2, vTexCoord) * opacity;

         float alpha = textureColor.a + textureColor2.a - textureColor.a * textureColor2.a;
         vec3 color = colorburn(textureColor, vTexCoord);
         gl_FragColor = vec4(color, alpha);
     }

);

const char *gl_fra_sub_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;
    uniform float opacity;

    void main(){
       vec4 color1 = texture2D(inputImageTexture, vTexCoord);
       vec4 color2 = texture2D(inputImageTexture2, vTexCoord);
       gl_FragColor = color1 - color2 * opacity;
    }
);

const char *gl_fra_overlay_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;

    uniform float opacity;

    void main()
    {
       vec4 base = texture2D(inputImageTexture, vTexCoord);
       vec4 overlay = texture2D(inputImageTexture2, vTexCoord) * opacity;

       float ra;
       if (2.0 * base.r < base.a) {
           ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
       } else {
           ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
       }

       float ga;
       if (2.0 * base.g < base.a) {
           ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
       } else {
           ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
       }

       float ba;
       if (2.0 * base.b < base.a) {
            ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
       } else {
           ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
       }

       float alpha = overlay.a + base.a - overlay.a * base.a;
       gl_FragColor = vec4(ra, ga, ba, alpha);
    }

);

const char *gl_fra_linearLight_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;

    uniform float opacity;

    void main()
    {
       vec4 base = texture2D(inputImageTexture, vTexCoord);

       vec4 overlay = texture2D(inputImageTexture2, vTexCoord);

       gl_FragColor = mix(base, base + 2. * overlay - vec4(1.), overlay.a * opacity);

    }

);

const char *gl_fra_linearBurn_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;

    uniform float opacity;

    vec3 blend(vec4 base, vec4 overlay) {
       vec3 baseRGB = base.rgb / (base.a + step(base.a, 0.0));
       vec3 overlayRGB = overlay.rgb / (overlay.a + step(overlay.a, 0.0));
       return (1.0 - overlay.a) * base.rgb + (1.0 - base.a) * overlay.rgb + base.a * overlay.a * clamp(baseRGB + overlayRGB - 1.0, 0.0, 1.0);
    }

    void main() {
        vec4 base = texture2D(inputImageTexture, vTexCoord);
        vec4 overlay = texture2D(inputImageTexture2, vTexCoord) * opacity;

        gl_FragColor = vec4(blend(base, overlay), base.a + overlay.a - base.a * overlay.a);
    }
);

const char *gl_fra_multiply_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;

    uniform float opacity;

    void main()
    {
      vec4 base = texture2D(inputImageTexture, vTexCoord);
      vec4 overlayer = texture2D(inputImageTexture2, vTexCoord) * opacity;

      gl_FragColor = overlayer * base + overlayer * (1.0 - base.a) + base * (1.0 - overlayer.a);
    }

);

const char *gl_fra_screen_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
      uniform sampler2D inputImageTexture;
      uniform sampler2D inputImageTexture2;
      uniform float opacity;
                                                  
      void main() {
          vec4 textureColor = texture2D(inputImageTexture, vTexCoord);
          vec4 textureColor2 = texture2D(inputImageTexture2, vTexCoord) * opacity;

          vec4 whiteColor = vec4(1.0);
          gl_FragColor = whiteColor - ((whiteColor - textureColor2) * (whiteColor - textureColor));
      }
);

const char *gl_fra_jdLut_blend_stds = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
     uniform sampler2D inputImageTexture;
     uniform sampler2D inputImageTexture2; // lookup texture
     uniform lowp float opacity;


     mat4 contrastMatrix( float contrast )
     {
         float t = ( 1.0 - contrast ) / 2.0;

         return mat4( contrast, 0.0, 0.0, 0.0,
                      0.0, contrast, 0.0, 0.0,
                      0.0, 0, contrast, 0.0,
                      t, t, t, 1.0 );
     }

     void main() {
         vec4 origin = texture2D(inputImageTexture, vTexCoord);
         vec3 textureColor = origin.rgb * 15. / 16. + vec3(1. / 32.);
         float blueColor = textureColor.b * 63.0;
         vec2 quad1;
         quad1.y = floor(floor(blueColor) / 8.0);
         quad1.x = floor(blueColor) - (quad1.y * 8.0);
         vec2 quad2;
         quad2.y = floor(ceil(blueColor) / 8.0);
         quad2.x = ceil(blueColor) - (quad2.y * 8.0);
         vec2 texPos1;
         texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
         texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
         vec2 texPos2;
         texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
         texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
         vec4 newColor1 = texture2D(inputImageTexture2, texPos1);
         vec4 newColor2 = texture2D(inputImageTexture2, texPos2);
         vec4 newColor = mix(newColor1, newColor2, fract(blueColor));

         newColor = contrastMatrix(16. / 15.) * newColor;

         gl_FragColor = mix(origin, vec4(newColor.rgb, origin.w), opacity);
     }
);

const char *gl_fra_lighten_blend_stds = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
                                             
   uniform sampler2D inputImageTexture;
   uniform sampler2D inputImageTexture2;

   uniform float opacity;

   void main() {
       vec4 textureColor = texture2D(inputImageTexture, vTexCoord);
       vec4 textureColor2 = texture2D(inputImageTexture2, vTexCoord) * opacity;

       gl_FragColor = max(textureColor, textureColor2);
   }
);

const char *gl_fra_lightercolor_blend_stds = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
                                             
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;

    uniform float opacity;

    vec3 blend(vec4 base, vec4 overlay) {
        vec3 baseRGB = base.rgb / (base.a + step(base.a, 0.0));
        vec3 overlayRGB = overlay.rgb / (overlay.a + step(overlay.a, 0.0));
        float baseSum = baseRGB.r * 0.299 + baseRGB.g * 0.587 + baseRGB.b * 0.114;
        float overlaySum = overlayRGB.r * 0.299 + overlayRGB.g * 0.587 + overlayRGB.b * 0.114;
        vec3 color = overlaySum > baseSum ? overlayRGB : baseRGB;
        return (1.0 - overlay.a) * base.rgb + (1.0 - base.a) * overlay.rgb + base.a * overlay.a * color;
    }

    void main() {
        vec4 texture1Color = texture2D(inputImageTexture, vTexCoord);

        vec4 outputColor = texture1Color;
        vec4 texture2Color = texture2D(inputImageTexture2, vTexCoord) * opacity;
        float flag1 = float(vTexCoord.x >= 0.0 && vTexCoord.x <= 1.0 && vTexCoord.y >= 0.0 && vTexCoord.y <= 1.0);
        texture2Color = mix(vec4(0.0), texture2Color, flag1);

        float alpha = texture1Color.a + texture2Color.a - texture1Color.a * texture2Color.a;
        vec3 color = blend(texture1Color, texture2Color);
        outputColor = vec4(color, alpha);

        gl_FragColor = outputColor;
    }

);

const char * gl_fra_divide_blend_stds = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;

    uniform float opacity;

    vec3 blend(vec4 base, vec4 overlay) {
        float odin = 1.0;
        if (base.a > 0.0) {
            odin = overlay.a / base.a;
        }

        float ra = 1.0 - step(base.r, 0.0);
        if (overlay.r > 0.0) {
            ra = base.r / overlay.r * odin;
        }

        float rg = 1.0 - step(base.g, 0.0);
        if (overlay.g > 0.0) {
            rg = base.g / overlay.g * odin;
        }

        float rb = 1.0 - step(base.b, 0.0);
        if (overlay.b > 0.0) {
            rb = base.b / overlay.b * odin;
        }

        vec3 color = clamp(vec3(ra, rg, rb), 0.0, 1.0);

        return (1.0 - overlay.a) * base.rgb + (1.0 - base.a) * overlay.rgb + base.a * overlay.a * color;
    }

    void main() {
       vec4 base = texture2D(inputImageTexture, vTexCoord);
       vec4 overlay = texture2D(inputImageTexture2, vTexCoord) * opacity;

       gl_FragColor = vec4(blend(base, overlay), base.a + overlay.a - base.a * overlay.a);
    }
);

const char *gl_fra_grain = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform float grain;
    uniform vec2 size;

    float random (vec2 st) {
      return fract(sin(dot(st.xy,
      vec2(12.9898,78.233)))*43758.5453123) - 0.5;
    }

    void main() {
      vec4 color = texture2D(inputImageTexture, vTexCoord);
      vec2 uv = st - mod(st, vec2(1. / size.x, 1. / size.y));
      float x = (uv.x + 4.0) * (uv.y + 4.0) * 10.0;
      vec4 rnd = vec4(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01) - 0.005) * grain;

      gl_FragColor = color + rnd;
    }
);

const char *gl_fra_GaussianBlur = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
     uniform sampler2D inputImageTexture;
     uniform vec2 size;
     uniform int radius;
     uniform int orientation;

     void main() {
         float weight = 0.;
         vec4 color = vec4(0.);
         if(orientation == 0){
             float dy = 1. / size.y;
             for (int i = - radius; i <= radius; i++){
                 float w = exp(- pow (float(i), 2.) / (2. * pow(float(radius) / 3.0, 2.)));
                 color += texture2D(inputImageTexture, vTexCoord + vec2(0.0 , dy * float(i))) * w;
                 weight += w;
             }
         }else{
             float dx = 1. / size.x;
             for (int i = - radius; i <= radius; i++){
                 float w = exp(- pow (float(i), 2.) / (2. * pow(float(radius) / 3.0, 2.)));
                 color += texture2D(inputImageTexture, vTexCoord + vec2(dx * float(i), 0.0)) * w;
                 weight += w;
             }
         }
         gl_FragColor =  color / weight;
     }
);

const char *gl_fra_hairColor = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
     uniform sampler2D inputImageTexture;
     uniform sampler2D hairColorTexture;

     float rgb2gray(vec3 color){
         return dot(color, vec3(0.299, 0.587, 0.114));
     }

     void main() {
         vec4 color = texture2D(inputImageTexture, vTexCoord);
         vec4 hairColor = texture2D(hairColorTexture, vTexCoord);
         gl_FragColor = vec4(hairColor.rgb * rgb2gray(color.rgb), rgb2gray(color.rgb));
     }
);

const char *gl_fra_localContrast = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    #define TWO_PI 6.28318530718
    uniform sampler2D inputImageTexture;
    uniform vec2 size;
    uniform float strength;
    uniform float radius;

    const vec3 W = vec3(0.299, 0.587, 0.114);
    const float eps = 0.00001;

    float rgb2gray(vec3 color){
        return dot(color.rgb, W);
    }


    void main() {
        vec3 result = vec3(0.);
        vec4 color0 = texture2D(inputImageTexture, vTexCoord);
        vec4 color = vec4(0.);
        vec3 weight = vec3(0.);
        vec3 weight_sum = vec3(0.);
        //    float radius = size.x * 0.04;
        float dUnit = radius / 4.0;
        float dTheta = TWO_PI / 12.0;
        if(radius < 4.0){
          dUnit = 1.0;
          dTheta = TWO_PI / 8.0;
        }
        for(float r = radius / 4.0; r <= radius; r += dUnit){
          for(float theta = 0.; theta < TWO_PI; theta += dTheta){
              color = texture2D(inputImageTexture, vTexCoord + r * vec2(cos(theta), sin(theta)) / size);
              weight = exp(-pow(color.rgb - color0.rgb, vec3(2.)) / 0.12);
              weight_sum += weight;
              result += weight * color.rgb;
          }
        }
        result = result / weight_sum;
        float a = strength;
        if(strength >.0){
          a = 1.5 * strength;
        }
        gl_FragColor = vec4(mix(color0.rgb, 2.0 * result * color0.rgb / (result + color0.rgb + 0.0001), -a), color0.a);
    }
);

const char *gl_fra_glowLight = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform float param1;
    const vec3 kLuminance = vec3(0.2125, 0.7154, 0.0721);

    vec3 saturation(vec3 color, float k) {
        float luminance = dot(kLuminance, color);
        vec3 luminanceColor = vec3(luminance);
        return color - (luminanceColor - color) * k;
    }
    const vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);

    vec3 luminance(vec3 color, float k) {
        return color + k;
    }

    vec3 contrast(vec3 color, float k) {
        return 0.5 + (color-0.5)*(1.0+k);
    }

    vec3 brightness(vec3 color, float k) {
        return color * (1.0+k);
    }

    void main() {
        vec4 textureColor = texture2D(inputImageTexture, vTexCoord);
        vec3 color = textureColor.rgb;
        color = saturation(color, -0.408);
        color = luminance(color, (0.071)*param1);
        color = contrast(color, (1.5534)*param1);
        color = brightness(color, -0.21*param1);

        gl_FragColor = vec4(color, textureColor.a);
    }

);

const char *gl_fra_vignette = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
     uniform sampler2D inputImageTexture;
     uniform float strength;
     uniform float blur;

     const float DMAX = 0.5;
     void main() {
         vec3 rgb = texture2D(inputImageTexture, vTexCoord).rgb;
         float d = distance(st, vec2(0.5, 0.5));
         float percent = smoothstep(DMAX * 0.5 + (DMAX * 0.5 - 0.01) * blur, DMAX * 2.0 - (DMAX - 0.01) * blur, d) * abs(strength);
         gl_FragColor = vec4(mix(rgb.x, step(0., strength) * 1.3, percent), mix(rgb.y, step(0., strength) * 1.3, percent), mix(rgb.z, step(0., strength) * 1.3, percent), 1.0);
     }
);

const char *gl_fra_colorGrain = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform vec2 size;
    uniform float grain;

    void main() {
       vec4 color = texture2D(inputImageTexture, vTexCoord);
       vec2 uv = vTexCoord - mod(vTexCoord, vec2(4. / size.x, 4. / size.y));

       float x = (uv.x + 4.0) * (uv.y + 4.0) * 24.0;
       float rr = (mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01) - 0.005) * grain;
       float rg = (mod((mod(x, 216.0) + 1.0) * (mod(x, 43.0) + 1.0), 0.01) - 0.005) * grain;
       float rb = (mod((mod(x * 9., 21.0) + 1.0) * (mod(x, 17.0) + 1.0), 0.01) - 0.005) * grain;

       color.rgb += vec3(rr, rg, rb);
       gl_FragColor = color;
    }

);

const char *gl_fra_glowColor = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform float brightnessValue;
    uniform float contrastValue;
    uniform float saturationValue;


    vec3 kLuminance = vec3(0.2125, 0.7154, 0.0721);


    vec3 saturation(vec3 color, float k) {
      float luminance = dot(kLuminance, color);
      vec3 luminanceColor = vec3(luminance);
      return color - (luminanceColor - color) * k;
    }
    vec3 luminance(vec3 color, float k) {
      return color + k;
    }

    vec3 contrast(vec3 color, float k) {
      return 0.5 + (color-0.5)*(1.0+k);
    }

    vec3 brightness(vec3 color, float k) {
      return color * (1.0+k);
    }

    void main()
    {
      vec4 texColor = texture2D(inputImageTexture, vTexCoord);
      vec3 color = texColor.rgb;
      color = saturation(color, saturationValue);
      color = luminance(color, brightnessValue);
      color = contrast(color, contrastValue);

      gl_FragColor = vec4(color, texColor.a);
    }
);

const char *gl_fra_lightArea = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    uniform float threshold;
                                          
    const vec3 kLuminance = vec3(0.2125, 0.7154, 0.0721);
                                          
    float rgb2gray(vec3 rgb){
        return dot(rgb, kLuminance);
    }
                                          
    void main() {
        vec4 col = texture2D(inputImageTexture, vTexCoord);

        col = mix(vec4(0.0), col, step(threshold, rgb2gray(col.rgb)));

        gl_FragColor = col;
    }
);

const char *gl_fra_whiteBalance = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
     uniform sampler2D inputImageTexture;
     uniform float temperature;
     uniform float tint;

     mat3 matRGBtoXYZ = mat3(
     0.4124564390896922, 0.21267285140562253, 0.0193338955823293,
     0.357576077643909, 0.715152155287818, 0.11919202588130297,
     0.18043748326639894, 0.07217499330655958, 0.9503040785363679
     );


     mat3 matXYZtoRGB = mat3(
     3.2404541621141045, -0.9692660305051868, 0.055643430959114726,
     -1.5371385127977166, 1.8760108454466942, -0.2040259135167538,
     -0.498531409556016, 0.041556017530349834, 1.0572251882231791
     );

     mat3 matAdapt = mat3(
     0.8951, -0.7502, 0.0389,
     0.2664, 1.7135, -0.0685,
     -0.1614, 0.0367, 1.0296
     );

     mat3 matAdaptInv = mat3(
     0.9869929054667123, 0.43230526972339456, -0.008528664575177328,
     -0.14705425642099013, 0.5183602715367776, 0.04004282165408487,
     0.15996265166373125, 0.0492912282128556, 0.9684866957875502
     );

     vec3 refWhite, refWhiteRGB;

     vec3 d, s;

     vec3 RGBtoXYZ(vec3 rgb){
         vec3 xyz, XYZ;
         xyz = matRGBtoXYZ * rgb;
         XYZ = matAdapt * xyz;
         XYZ *= d/s;
         xyz = matAdaptInv * XYZ;

         return xyz;
     }

     vec3 XYZtoRGB(vec3 xyz){
         vec3 rgb, RGB;

         RGB = matAdapt * xyz;
         rgb *= s/d;
         xyz = matAdaptInv * RGB;

         rgb = matXYZtoRGB * xyz;

         return rgb;
     }

     float Lum(vec3 c){
         return 0.299*c.r + 0.587*c.g + 0.114*c.b;
     }

     vec3 ClipColor(vec3 c){
         float l = Lum(c);
         float n = min(min(c.r, c.g), c.b);
         float x = max(max(c.r, c.g), c.b);

         if (n < 0.0) c = (c-l)*l / (l-n) + l;
         if (x > 1.0) c = (c-l) * (1.0-l) / (x-l) + l;

         return c;
     }

     vec3 SetLum(vec3 c, float l){
         float d = l - Lum(c);

         c.r = c.r + d;
         c.g = c.g + d;
         c.b = c.b + d;

         return ClipColor(c);
     }

     vec3 D50 = vec3(0.96422, 1.0, 0.82521);
     vec3 D65 = vec3(0.95047, 1.0, 1.08883);

     vec3 CCT2K = vec3(1.274335, 1.0, 0.145233);
     vec3 CCT4K = vec3(1.009802, 1.0, 0.644496);
     vec3 CCT20K = vec3(0.995451, 1.0, 1.886109);

     void main() {
         vec4 col = texture2D(inputImageTexture, vTexCoord);

         vec3 to, from;

         if (temperature < 0.0) {
             to = CCT20K;
             from = D65;
         } else {
             to = CCT4K;
             from = D65;
         }

         vec3 base = col.rgb;
         float lum = Lum(base);
         float temp = abs(temperature) * (1.0 - pow(lum, 2.72));

         refWhiteRGB = from;
         refWhite = vec3(mix(from.x, to.x, temp), mix(1.0, 0.9, tint), mix(from.z, to.z, temp));
         refWhite = mix(refWhiteRGB, refWhite, col.a);

         d = matAdapt * refWhite;
         s = matAdapt * refWhiteRGB;
         vec3 xyz = RGBtoXYZ(base);
         vec3 rgb = XYZtoRGB(xyz);
         vec3 res = rgb * (1.0 + (temp + tint) / 10.0);
         gl_FragColor = vec4(mix(base, res, col.a), col.a);
     }

);

//
const char *gl_fra_MixMask = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture1;
    uniform sampler2D inputImageTexture2;
    uniform sampler2D maskTexture;

    uniform float opacity;


    void main() {

        vec4 col1 = texture2D(inputImageTexture1, vTexCoord);
        vec4 col2 = texture2D(inputImageTexture2, vTexCoord);
        gl_FragColor = mix(col1, col2, opacity * texture2D(maskTexture, vTexCoord).r);
    }

);

const char *gl_fra_hsl = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D inputImageTexture;
    const float red = 0.027692;
    const float orange = 0.077692;
    const float yellow = 0.162857;
    const float green = 0.445586;
    const float blue = 0.615317;
    const float purple = 0.785193;
    const float magenta = 0.923846;

    uniform vec3 redShift;
    uniform vec3 orangeShift;
    uniform vec3 yellowShift;
    uniform vec3 greenShift;
    uniform vec3 blueShift;
    uniform vec3 purpleShift;
    uniform vec3 magentaShift;

    float hue2rgb(float M1, float M2, float hue) {
      float c;
      if (hue < 0.0) {
          hue += 1.0;
      } else if (hue > 1.0) {
          hue -= 1.0;
      }
      
      if ((6.0 * hue) < 1.0) {
          c = (M1 + (M2 - M1) * hue * 6.0);
      } else if ((2.0 * hue) < 1.0) {
          c = M2;
      } else if ((3.0 * hue) < 2.0) {
          c = (M1 + (M2 - M1) * ((2.0/3.0) - hue) * 6.0);
      } else {
          c = M1;
      }
      return c;
    }

    vec3 rgb2hsl(vec3 color ){
      vec3 hsl = vec3(0.0, 0.0, 0.0);
      
      float fmin = min(min(color.r, color.g), color.b);
      float fmax = max(max(color.r, color.g), color.b);
      float delta = fmax - fmin;
      
      hsl.z = (fmax + fmin) / 2.0;
      
      if (delta == 0.0)
      {
          hsl.x = 0.0;
          hsl.y = 0.0;
      } else
      {
          if (hsl.z < 0.5) {
              hsl.y = delta / (fmax + fmin);
          } else {
              hsl.y = delta / (2.0 - fmax - fmin);
          }
          float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;
          float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;
          float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;
          
          if (color.r == fmax) {
              hsl.x = deltaB - deltaG;
          } else if (color.g == fmax) {
              hsl.x = (1.0 / 3.0) + deltaR - deltaB;
          } else if (color.b == fmax) {
              hsl.x = (2.0 / 3.0) + deltaG - deltaR;
          }
          if (hsl.x < 0.0) {
              hsl.x += 1.0;
          } else if (hsl.x > 1.0) {
              hsl.x -= 1.0;
          }
      }
      
      return hsl;
    }

    vec3 smoothTreatment(vec3 hsl, vec3 shiftEdge)
    {
      float M1 = .0;
      float M2 = .0;
      float hue = hsl.x * shiftEdge.x;
      float saturation = hsl.y * shiftEdge.y;
      float lightness = hsl.z * shiftEdge.z;
      
      mediump vec3 color = hsl;
      if (saturation == 0.0) {
          color.r = lightness;
          color.g = lightness;
          color.b = lightness;
      } else {
          if (lightness < 0.5) {
              M2 = lightness * (1.0 + saturation);
          } else {
              M2 = lightness + saturation - lightness * saturation;
          }
          M1 = (2.0 * lightness - M2);
          color.r = hue2rgb(M1, M2, hue + (1.0/3.0));
          color.g = hue2rgb(M1, M2, hue);
          color.b = hue2rgb(M1, M2, hue - (1.0/3.0));
      }
      return color;
    }

    vec4 HSLFunc(vec4 pixel,
                        vec3 redShift, vec3 orangeShift, vec3 yellowShift, vec3 greenShift,
                        vec3 blueShift, vec3 purpleShift, vec3 magentaShift)
    {
      vec3 colorRGB = pixel.rgb;
      vec3 hsl = rgb2hsl(colorRGB);
      float hue = hsl.x;
      
      if (hue >= red && hue < orange){
          hsl = smoothTreatment(hsl, orangeShift);
          
      } else if (hue >= orange && hue < yellow){
          hsl = smoothTreatment(hsl, yellowShift);
          
      } else if (hue >= yellow && hue < green){
          hsl = smoothTreatment(hsl,greenShift);
          
      } else if (hue >= green && hue < blue){
          hsl = smoothTreatment(hsl, blueShift);
          
      } else if (hue >= blue && hue < purple){
          hsl = smoothTreatment(hsl, purpleShift);
          
      } else if (hue >= purple && hue < magenta){
          hsl = smoothTreatment(hsl, magentaShift);
          
      } else {
          hsl = smoothTreatment(hsl, redShift);
          
      }
      return vec4(hsl, 1.0);
    }

    void main()
    {
      vec4 inColor = texture2D(inputImageTexture, vTexCoord);
      gl_FragColor = HSLFunc(inColor, redShift, orangeShift, yellowShift, greenShift, blueShift, purpleShift, magentaShift);
    }
);

const char *gl_vex_BilateralBlur = SHADER_SRC(
            SHDR_VERT_HEAD_NORM

            uniform vec2 uStep;

            const lowp int GAUSSIAN_SAMPLES = 9;
            SHDR_VERT_VARYING vec2 blurCoordinates[GAUSSIAN_SAMPLES];

            void main() {
                gl_Position = aPos;
                vTexCoord = aTexCoord.xy;

                int multiplier = 0;
                vec2 blurStep;

                for (int i = 0; i < GAUSSIAN_SAMPLES; i++) {
                    multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));

                    blurStep = float(multiplier) * uStep;
                    blurCoordinates[i] = aTexCoord.xy + blurStep;
                }
            }

);


const char *gl_fra_BiLateralBlur = SHADER_SRC(
     SHDR_FRAG_HEAD(highp)
     uniform sampler2D uTexture;
     const lowp int GAUSSIAN_SAMPLES = 9;

     SHDR_FRAG_VARYING vec2 blurCoordinates[GAUSSIAN_SAMPLES];

     uniform float uThreshold;

     void main(){
         vec4 outColor;
         lowp vec4 centralColor;
         lowp float gaussianWeightTotal;
         lowp vec4 sum;
         lowp vec4 sampleColor;
         lowp float distanceFromCentralColor;
         lowp float gaussianWeight;

         centralColor = texture2D(uTexture, blurCoordinates[4]);
         gaussianWeightTotal = 0.18;
         sum = centralColor * 0.18;
         // todo for循环加权重的数组来简化代码
         sampleColor = texture2D(uTexture, blurCoordinates[0]);
         //percent = max((uThreshold - distance(centralColor, sampleColor))/uThreshold,0.0);
         //uThreshold很大时，相当于都模糊 不保留边缘
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;

         sampleColor = texture2D(uTexture, blurCoordinates[1]);
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;

         sampleColor = texture2D(uTexture, blurCoordinates[2]);
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;

         sampleColor = texture2D(uTexture, blurCoordinates[3]);
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;

         sampleColor = texture2D(uTexture, blurCoordinates[5]);
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;

         sampleColor = texture2D(uTexture, blurCoordinates[6]);
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;

         sampleColor = texture2D(uTexture, blurCoordinates[7]);
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;

         sampleColor = texture2D(uTexture, blurCoordinates[8]);
         distanceFromCentralColor = min(distance(centralColor, sampleColor), uThreshold)/uThreshold;
         gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
         gaussianWeightTotal += gaussianWeight;
         sum += sampleColor * gaussianWeight;
         outColor = sum / gaussianWeightTotal;
         gl_FragColor = outColor;
     }

);


const char *gl_fra_Toonify = SHADER_SRC(
        SHDR_FRAG_HEAD_NORM
        uniform sampler2D uTexture;
        uniform vec2 uSize;
        uniform float uEdgeBlackLevel;
        uniform vec4 uParams[20];
        uniform vec2 uNorm;
        uniform vec2 uFrag;
                                        
        const float EQUAL_THRESHOLD = 0.0001;
        const float GAMMA = 2.2;
        const float GAMMA_INVERSE = 1.0/2.2;
        const float paramP = 2.0;
        const int uCount = 20;
        const float uAlpha = 1.0;
        const float edgeThreshold = 0.5;
        const float paramT = 0.0;
        const float uType = 3.0;
        const float uLevel = 20.0;

        void main() {
            vec4 outColor;
            vec2 uv = vTexCoord;

            // 卡通化
            vec4 originColor = texture2D(uTexture, uv);
            vec3 posterizedColor = originColor.rgb;

            posterizedColor = pow(posterizedColor, vec3(GAMMA_INVERSE));
            float greyscale = 0.299 * posterizedColor.r + 0.587 * posterizedColor.g + 0.114 * posterizedColor.b;
            float level = floor(greyscale * uLevel + 0.5) / uLevel;
            float adjustment = level / greyscale;
            posterizedColor *= adjustment;
            posterizedColor = pow(posterizedColor, vec3(GAMMA));

            // DoG 计算像素值变化的梯度 以保留细节或者提取线稿\n"
            vec3 destColor = vec3(0.0);
            int maxNumberIteration = uCount;
            vec2 sum = vec2(0.0);
            for (int cnt = 0; cnt < maxNumberIteration; ++cnt) {
                int i = int(uParams[cnt].x);
                int j = int(uParams[cnt].y);
                vec2 kernel = vec2(uParams[cnt].z, uParams[cnt].w);
                vec4 c = texture2D(uTexture, uv +(vec2(float(i), float(j))) * uFrag);
                vec2 L = vec2(0.299 * c.r + 0.587*c.g + 0.114*c.b);
                sum += kernel * L;
            }
            sum /= uNorm;
            
            float H = 100.0 * (sum.x - uEdgeBlackLevel * sum.y);
            // 描边
            float edge = mix(1.0, 2.0 * smoothstep(-2.0, 2.0, paramP * H), step(H,EQUAL_THRESHOLD));
            edge = pow(edge,10.0);
            float factor = step(uType,2.5);
            vec3 baseColor = mix(posterizedColor,vec3(1.0,1.0,1.0),factor);
            vec3 blendColor = mix(baseColor,baseColor * edge,uAlpha);
            outColor = vec4(blendColor, originColor.a);
            gl_FragColor = outColor;
        }
);

const char *gl_fra_glassTile = SHADER_SRC(
    SHDR_FRAG_HEAD_NORM
    uniform sampler2D uTexture;
    uniform vec2 uSize;
    uniform float GRID_SIZE;
    uniform float uIntencity;


      float boxSDF(vec2 P, vec2 R) {
          vec2 q = abs(P) - R;
          return length(max(q, 0.0));
      }

      // 折射的法线方向
      vec3 N(vec2 P, vec2 R) {
          vec2 q = abs(P);
          vec2 dis = sign(P);
          if (q.x > R.x && q.y > R.y) {
              vec2 d = abs(q-R);
              vec2 n = normalize(d*dis);
              float cosX = 1.0;
              if (q.x > q.y) {
                  cosX = dot(normalize(d), vec2(1.0, 0.0));
              } else {
                  cosX = dot(normalize(d), vec2(0.0, 1.0));
              }
              return vec3(n, abs(cosX));
          } else if (q.x > q.y) {
              if (P.x > 0.0) {
                  return vec3(1.0, 0.0, 1.0);
              } else {
                  return vec3(-1.0, 0.0, 1.0);
              }
          } else {
              if (P.y > 0.0) {
                  return vec3(0.0, 1.0, 1.0);
              } else {
                  return vec3(0.0, -1.0, 1.0);
              }
          }
      }

      // 单元格玻璃效果
      vec2 ProjectCoordsGlassCell(vec2 normCoords) {
          vec2 newUV = normCoords * 5.0;
          float d = boxSDF(newUV, vec2(3.0));
          if (abs(d)<=0.0) {
              return normCoords;
          }
          vec3 n = N(newUV, vec2(3.0));
          d *= n.z;
          d /=2.0;
          float i = 1.0 - abs(d);
          
          // 计算uv 坐标偏移
          vec2 outUV = normCoords - n.xy*d * uIntencity *i;
          return outUV;
      }

    void main() {
        vec2 uv = vTexCoord;
        vec2 gridCoordsRaw = uv * GRID_SIZE;
        float GRID_HALF_SIZE = 0.5*1.0/GRID_SIZE;
        // 当前单元格的中心点
        vec2 cellMiddlePos = (floor(gridCoordsRaw)/ GRID_SIZE + GRID_HALF_SIZE);

        // 将每个单元格的坐标映射到 [-1, 1]
        vec2 cellDelta = (fract(gridCoordsRaw) - 0.5) * 2.0;
        //构建一个玻璃球体
        cellDelta = ProjectCoordsGlassCell(cellDelta);

        vec2 srcTexCoord = cellMiddlePos + cellDelta * GRID_HALF_SIZE;

        gl_FragColor = texture2D(uTexture, fract(srcTexCoord));
    }

);


const char *gl_vex_DispCut3D = SHADER_SRC(

        SHDR_VERT_HEAD_NORM

        const float EQUAL_THRESHOLD = 0.0001;

        SHDR_VERT_ATTRIBUTE vec4 aParam;
        SHDR_VERT_VARYING float vRotate;
        SHDR_VERT_VARYING float vPointSize;
        SHDR_VERT_VARYING float vOffsetSpirit;
        SHDR_VERT_VARYING vec3 vOffsetPosition;
        SHDR_VERT_VARYING float vProgress;

        uniform float uPointSize;
        uniform float uStrength;
        uniform float uExtralCutScale;
        uniform float uSpeed;

        void main() {
            vOffsetPosition = vec3(0.0,0.0,0.0);
            vec3 loc = aPos.xyz;
            float val_Rand = aParam.y;
            float val_Rand2 = aParam.z;
            float val_speed = (0.5 + 1.6 * val_Rand) * uSpeed;
            vOffsetSpirit = aParam.x;
            vProgress = mod(max(uStrength - aParam.w, 0.0), 1.0001);
            vProgress = smoothstep(0.0, 1.0, vProgress);
            vRotate = 2.5 * val_Rand2;
            vTexCoord =aPos.xy;

            vPointSize = 0.0;
            if(vProgress > EQUAL_THRESHOLD) {
                vPointSize = uPointSize * (0.8 + vProgress * 1.5 * uExtralCutScale);
            }
            gl_Position = vec4(loc, 1.0);
            gl_Position.x += step(vProgress, EQUAL_THRESHOLD) * 1000.0;
            gl_PointSize = vPointSize;
        }

);

const char *gl_fra_DispCut3D = SHADER_SRC(

        SHDR_FRAG_HEAD_NORM

        SHDR_FRAG_VARYING float vPointSize;
        SHDR_FRAG_VARYING float vRotate;
        SHDR_FRAG_VARYING float vOffsetSpirit;

        uniform vec2 uSize;
        uniform float uDivision;

        uniform sampler2D uTexture;

        vec2 getFlipY(vec2 loc) {
            return vec2(loc.x, 1.0 - loc.y);
        }

        vec2 getRotUV(vec2 loc, float rot) {
            float sinA = sin(rot);
            float cosA = cos(rot);
            mat2 rot_mat = mat2(cosA, -sinA, sinA, cosA);
            vec2 loc_tmp = loc - vec2(0.5);
            return loc_tmp * rot_mat + vec2(0.5);
        }

        vec2 getStepUV(vec2 loc, float step, float off) {
            vec2 vec_off = vec2(0.0, off * step);
            return (loc) * vec2(1.0, step) + vec_off;
        }

        vec2 getTexUV(vec2 loc_tex, vec2 loc_pt) {
            vec2 uv = vec2(loc_pt.x, uSize.y - loc_pt.y) / uSize;
            vec2 dst = (loc_tex - vec2(0.5)) * vPointSize / uSize + uv;
            return dst;
        }

        void main() {
            vec2 loc_rot = getRotUV(gl_PointCoord, vRotate);
            vec2 loc_stp = getStepUV(loc_rot, uDivision, vOffsetSpirit);
            vec4 clr_spt = SHDR_TEXTURE2D(uTexture, loc_stp);
            vec4 clr = vec4(1.0, 1.0, 1.0, clr_spt.r);
            vec4 outColor = clr;
            SHDR_OUTCOLOR
        }
);


/**
* 点精灵  gl_PointCoord  坐标系 左上角 (0,0), 右下角 (1,1)
*/

const char *gl_vex_DispSpread3D = SHADER_SRC(
        attribute vec3 aPos; // x, y, z
        attribute vec2 aTexCoord;
        attribute vec2 aLife; // 开始时间，持续时间
        attribute vec3 aSpeed; // 粒子旋转角度、运动速度增益、粒子旋转速度
                                             
        SHDR_VERT_VARYING vec4 vPosition;
        SHDR_VERT_VARYING vec2 vTexCoord;

        const float EQUAL_THRESHOLD = 0.0001; // 用于判断是否是0

        SHDR_VERT_VARYING float vProgress;
        SHDR_VERT_VARYING float vAngle;
        SHDR_VERT_VARYING float vPointSize;
        SHDR_VERT_VARYING float vRotateSpeed;

        uniform float uPointSize;
        uniform float uTime;
        uniform float uSpeed;
        uniform vec3 uCenter; // 发射器中心
                                             
        void main() {
            vec3 V = aPos - uCenter; // 粒子运动方向
            float t = uTime - aLife.x; // 当前时间
            t = mod(uTime, aLife.y); // 时间
            float s = uSpeed + aSpeed.y; // 速度
            vec3 P1 = aPos + V*s*t; // 时间
            
            vPosition = vec4(P1, 1.0);
            vTexCoord = aTexCoord;
            
            vProgress = t/aLife.y;
            vAngle = radians(aSpeed.x);
            vPointSize = uPointSize;
            vRotateSpeed = aSpeed.z;
            
            gl_Position = vPosition;
            if(vProgress < EQUAL_THRESHOLD) {
                gl_Position = vec4(1000.0, 0.0, 0.0, 1.0);
            }
            gl_PointSize = vPointSize;
        }

);

const char *gl_fra_DispSpread3D = SHADER_SRC(

         SHDR_PRECISION_NORM
         const float EQUAL_THRESHOLD = 0.0001;
         SHDR_FRAG_VARYING vec4 vPosition;
         SHDR_FRAG_VARYING vec2 vTexCoord;
         SHDR_FRAG_VARYING float vProgress;
         SHDR_FRAG_VARYING float vAngle;
         SHDR_FRAG_VARYING float vRotateSpeed;
         SHDR_FRAG_VARYING float vPointSize;
         SHDR_FRAG_VARYING vec2 vTexCoord;
                                             
        void main() {
            gl_FragColor = vec4(1.0);
        }

);

const char *gl_frg_CloneStamp = SHADER_SRC(
       SHDR_FRAG_HEAD_NORM
       uniform sampler2D uTexture;
       uniform sampler2D uMask;
       uniform sampler2D uEage;
       uniform vec2 uDistence_AB;
       uniform vec2 uDistence_AC;
       uniform int uFlip; 
       uniform vec2 uMaskCenter;
       uniform vec2 uSize;
       uniform float uAlpha;
       uniform float uIsShowEageB;
       uniform float uIsShowEageC;
       uniform float uMaskScale;
       uniform float uMaskAngleC;
       uniform float uMaskAngleB;
       uniform vec3 uEageColorB;
       uniform vec3 uEageColorC;
       void main() {
//           vec2 distence_AB = uDisplacement;
//           vec2 distence_AC = vec2(0.1, 0.1);
           
           vec2 distence_AB = uDistence_AB;
           vec2 distence_AC = uDistence_AC;
           
           
           vec2 B_UV = vTexCoord;
           vec2 A_UV = vTexCoord - distence_AB;
           vec2 C_UV = A_UV;
           vec2 mask_UV = vTexCoord;
           
           vec2 B_mask_UV = vTexCoord - distence_AB;
           vec2 C_mask_UV = vTexCoord - distence_AC;
           
           vec2 B_Eage_UV = vTexCoord - distence_AB;
           vec2 C_Eage_UV = vTexCoord - distence_AC;
           
           if (uFlip != 0) {
               C_UV -= uMaskCenter;
               C_UV.x = C_UV.x*(-1.0);
               C_UV += uMaskCenter;
               
               B_Eage_UV -= uMaskCenter;
               B_Eage_UV.x = B_Eage_UV.x*(-1.0);
               B_Eage_UV += uMaskCenter;
               
               B_mask_UV -= uMaskCenter;
               B_mask_UV.x = B_mask_UV.x*(-1.0);
               B_mask_UV += uMaskCenter;
               
               C_mask_UV -= uMaskCenter;
               C_mask_UV.x = C_mask_UV.x*(-1.0);
               C_mask_UV += uMaskCenter;
           }
           float sin_angleC = sin(uMaskAngleC);
           float cos_angleC = cos(uMaskAngleC);
           mat2 rotatematC = mat2(cos_angleC, sin_angleC, -sin_angleC, cos_angleC);
           
           C_Eage_UV -= uMaskCenter;
           C_Eage_UV *= uSize;
           C_Eage_UV = C_Eage_UV*uMaskScale;
           C_Eage_UV = rotatematC*C_Eage_UV;
           C_Eage_UV /= uSize;
           C_Eage_UV += uMaskCenter;
           
           C_mask_UV -= uMaskCenter;
           C_mask_UV *= uSize;
           C_mask_UV = C_mask_UV*uMaskScale;
           C_mask_UV = rotatematC*C_mask_UV;
           C_mask_UV /= uSize;
           C_mask_UV += uMaskCenter;
           
           float sin_angleB = sin(uMaskAngleB);
           float cos_angleB = cos(uMaskAngleB);
           mat2 rotatematB = mat2(cos_angleB, sin_angleB, -sin_angleB, cos_angleB);
           
           B_Eage_UV -= uMaskCenter;
           B_Eage_UV *= uSize;
           B_Eage_UV = B_Eage_UV*uMaskScale;
           B_Eage_UV = rotatematB*rotatematC*B_Eage_UV;
           B_Eage_UV /= uSize;
           B_Eage_UV += uMaskCenter;
           
           B_mask_UV -= uMaskCenter;
           B_mask_UV *= uSize;
           B_mask_UV = B_mask_UV*uMaskScale;
           B_mask_UV = rotatematB*rotatematC*B_mask_UV;
           B_mask_UV /= uSize;
           B_mask_UV += uMaskCenter;
           
          
           C_UV -= uMaskCenter;
           C_UV *= uSize;
           C_UV = rotatematB*C_UV;
           C_UV /= uSize;
           C_UV += uMaskCenter;
           C_UV = C_UV + distence_AC;
           
           B_mask_UV = clamp(B_mask_UV, 0.0, 1.0);
           C_mask_UV = clamp(C_mask_UV, 0.0, 1.0);
           
           vec4 C_Eage = texture2D(uEage, C_Eage_UV)*(step(0.0, C_Eage_UV.x) - step(1.0, C_Eage_UV.x))*(step(0.0, C_Eage_UV.y) - step(1.0, C_Eage_UV.y));
           vec4 B_Eage = texture2D(uEage, B_Eage_UV)*(step(0.0, B_Eage_UV.x) - step(1.0, B_Eage_UV.x))*(step(0.0, B_Eage_UV.y) - step(1.0, B_Eage_UV.y));
           
           vec4 B_color = texture2D(uTexture, B_UV);
           
           vec3 outColor = vec3(0.0);
           if (C_UV.x < 0.0 || C_UV.x > 1.0 || C_UV.y < 0.0 || C_UV.y > 1.0) {
               outColor = B_color.rgb;
           } else {
               vec4 C_color = texture2D(uTexture, C_UV);
               vec4 mask_color = texture2D(uMask, B_mask_UV)*uAlpha;
               outColor = mix(B_color.rgb, C_color.rgb, mask_color.rgb);
           }
           outColor = mix(outColor, uEageColorC, C_Eage.rgb * uIsShowEageC);
           outColor = mix(outColor, uEageColorB, B_Eage.rgb*uIsShowEageB);
           outColor = clamp(outColor, 0.0, 1.0);
           
           gl_FragColor = vec4(outColor, B_color.a);
       }
);

const char *gl_fra_BoxBlur = SHADER_SRC(
     SHDR_FRAG_HEAD_NORM
                                             
     uniform sampler2D inputImageTexture;
     uniform vec2 size;
     uniform int radius;
     uniform int orientation;
     uniform int step;
     void main() {
         float weight = 0.;
         vec4 color = vec4(0.);
         if(orientation == 0){
             float dy = 1. / size.y;
             for (int i = - radius; i <= radius; i+=step){
                 float w = 1.0;
                 color += texture2D(inputImageTexture, vTexCoord + vec2(0.0 , dy * float(i))) * w;
                 weight += w;
             }
         }else{
             float dx = 1. / size.x;
             for (int i = - radius; i <= radius; i+=step){
                 float w = 1.0;
                 color += texture2D(inputImageTexture, vTexCoord + vec2(dx * float(i), 0.0)) * w;
                 weight += w;
             }
         }
         gl_FragColor =  color / weight;
     }
);

const char *gl_fra_Sobel_edge = SHADER_SRC(
      SHDR_FRAG_HEAD_NORM
      uniform sampler2D uOriginMask;
      uniform vec2 uSize;
      uniform float gx_core[9];
      uniform float gy_core[9];
                                          
      float sobel(vec2 coord, vec2 size) {
          float gx = 0.0;
          float gy = 0.0;

          for (float i = 0.0; i <= 2.0; i+=1.0) {
              for (float j = 0.0; j <= 2.0; j+=1.0) {
                  vec2 offset = vec2(i-1.0,j-1.0);
                  vec2 uv = coord + offset;
                  uv = uv/size;
                  int index = int(i*3.0+j);
                  float a = (step(0.0, uv.x) - step(1.0, uv.x))*(step(0.0, uv.y) - step(1.0, uv.y));
                  gx += texture2D(uOriginMask, uv).r*gx_core[index] * a;
                  gy += texture2D(uOriginMask, uv).r*gy_core[index] * a;
              }
          }
          return sqrt(gx*gx+gy*gy);
      }
      void main() {
          float v = sobel(vTexCoord*uSize, uSize);
          gl_FragColor = vec4(vec3(v), 1.0);
      }
);

const char *gl_fra_lut = SHADER_SRC(
      SHDR_FRAG_HEAD_NORM
      uniform sampler2D uTexture;
      uniform sampler2D uLut;
      uniform float uAlpha;
      uniform vec2 uSize;

      void main() {
          vec4 origin = texture2D(uTexture, vTexCoord);

          vec3 textureColor = origin.rgb;

          float blueColor = textureColor.b * 63.0;
          vec2 quad1;
          quad1.y = floor(floor(blueColor) / 8.0);
          quad1.x = floor(blueColor) - (quad1.y * 8.0);
          vec2 quad2;
          quad2.y = floor(ceil(blueColor) / 8.0);
          quad2.x = ceil(blueColor) - (quad2.y * 8.0);
          vec2 texPos1;
          texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
          texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
          texPos1.y = 1.0 - texPos1.y;
          vec2 texPos2;
          texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
          texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
          texPos2.y = 1.0 - texPos2.y;
          vec4 newColor1 = texture2D(uLut, texPos1);
          vec4 newColor2 = texture2D(uLut, texPos2);
          vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
          gl_FragColor = mix(origin, newColor, uAlpha);
      }
);

//const char *
void regShaderForCXM(map<string, shared_ptr<STDSShaderStream>> &shaderMap) {
    shaderMap.insert(make_pair(string(kShaderSRCSkinDetect), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_skin_delect)));
    shaderMap.insert(make_pair(string(kShaderSRCDefault), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_default)));
    shaderMap.insert(make_pair(string(kShaderSRCSkinLutDetect), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_skin_lut_delect)));
    shaderMap.insert(make_pair(string(kShaderSRCSkinWiten), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_skin_whiten)));
    shaderMap.insert(make_pair(string(kShaderSRCMosaic), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_mosaic)));
    shaderMap.insert(make_pair(string(kShaderSRCTransformmation), make_shared<STDSShaderStream>(gl_shader_vex_3D, gl_fra_Tex_Alpha)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendMirrorLinear_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_mirror_linear_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendAdd_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_add_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendHardlight_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_hardlight_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendBloom_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_bloom_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendNormal_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_normal_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendLineardodge_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_lineardodge_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendColorBurn_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_colorburn_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendSub_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_sub_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendOverlay_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_overlay_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendLinearLight_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_linearLight_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendLinearBurn_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_linearBurn_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendMultiply_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_multiply_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendScreen_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_screen_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendJdLut_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_jdLut_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendLighten_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_lighten_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendLighterColor_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_lightercolor_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCBlendDivide_STDS), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_divide_blend_stds)));
    shaderMap.insert(make_pair(string(kShaderSRCVignette), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_vignette)));
    shaderMap.insert(make_pair(string(kShaderSRCColorGrain), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_colorGrain)));
    shaderMap.insert(make_pair(string(kShaderSRCGlowColor), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_glowColor)));
    shaderMap.insert(make_pair(string(kShaderSRCLightArea), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_lightArea)));
    shaderMap.insert(make_pair(string(kShaderSRCWhiteBalance), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_whiteBalance)));
    shaderMap.insert(make_pair(string(kShaderSRCMixMask), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_MixMask)));
    shaderMap.insert(make_pair(string(kShaderSRCHSL), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_hsl)));
    //
    
    shaderMap.insert(make_pair(string(kShaderSRCGrain), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_grain)));
    shaderMap.insert(make_pair(string(kShaderSRCGaussianBlur), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_GaussianBlur)));
    shaderMap.insert(make_pair(string(kShaderSRCHairColor), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_hairColor)));
    shaderMap.insert(make_pair(string(kShaderSRCContrast), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_localContrast)));
    shaderMap.insert(make_pair(string(kShaderSRCGlowLight), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_glowLight)));
    
    // puzzle
    shaderMap.insert(make_pair(string(kShaderSRCMaskKey), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_maskKey)));
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleUnit), make_shared<STDSShaderStream>(gl_shader_vex_3D, gl_fra_puzzleUnit)));
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleStarsMask), make_shared<STDSShaderStream>(gl_shader_vex_3D, gl_fra_puzzleStarsMask)));
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleStars), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_puzzleStars)));
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleBreak), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_puzzleBreak)));
    
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleGrain), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_puzzleGrain)));
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleGlass), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_puzzleGlass)));
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleRainbow), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_puzzleRainbow)));
    shaderMap.insert(make_pair(string(kShaderSRCPuzzleCartoon), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_puzzleCartoon)));
    
    shaderMap.insert(make_pair(string(kShaderSRCSolidColor), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_SolidColor)));
    
    //kShaderSRCBiLateralBlur
    shaderMap.insert(make_pair(string(kShaderSRCBiLateralBlur), make_shared<STDSShaderStream>(gl_vex_BilateralBlur, gl_fra_BiLateralBlur)));
    //kShaderSRCCartoon
    shaderMap.insert(make_pair(string(kShaderSRCCartoon), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_Toonify)));
    shaderMap.insert(make_pair(string(kShaderSRCGlassTile), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_glassTile)));
    // 粒子消散
    shaderMap.insert(make_pair(string(kShaderSRCParticleCutout), make_shared<STDSShaderStream>(gl_vex_DispCut3D, gl_fra_DispCut3D)));
    shaderMap.insert(make_pair(string(kShaderSRCParticleDissipate), make_shared<STDSShaderStream>(gl_vex_DispSpread3D, gl_fra_DispSpread3D)));
    //仿制图章
    shaderMap.insert(make_pair(string(kShaderSRCCloneStamp), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_frg_CloneStamp)));
    shaderMap.insert(make_pair(string(kShaderSRCBoxBlur), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_BoxBlur)));
    //
    shaderMap.insert(make_pair(string(kShaderSRCSobelEage), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_Sobel_edge)));
    //
    shaderMap.insert(make_pair(string(kShaderSRCLut), make_shared<STDSShaderStream>(gl_shader_vex_2D, gl_fra_lut)));
}
